{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 链结构（chain）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. LLM chain（单链结构）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.llms import Tongyi\n",
    "import os\n",
    "os.environ[\"DASHSCOPE_API_KEY\"]= \"sk-9d8f1914800e497f8717144e860f99bc\"\n",
    "llm = Tongyi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import PromptTemplate, LLMChain\n",
    "prompt_template = \"给我一个很土但是听起来很好养活的男孩小明\"\n",
    "llm_chain = LLMChain(\n",
    "    llm = llm,\n",
    "    prompt = PromptTemplate.from_template(prompt_template)   \n",
    ")\n",
    "llm_chain.predict()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Router Chain（多链并行）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "naming_template = \"\"\"你是一个非常有创意的起名专家.\\\n",
    "    你非常擅长给新生儿们起好听的，富含寓意的名字.\\\n",
    "    用中文给出回答.\n",
    "        \n",
    "    这里是问题：\n",
    "    {input}\"\"\"\n",
    "math_template = \"\"\"You are a very good mathematician. You are great at answering math questions. \n",
    "You are so good because you are able to break down hard problems into their component parts, \n",
    "answer the component parts, and then put them together to answer the broader question.\n",
    "\n",
    "Here is a question:\n",
    "{input}\"\"\"\n",
    "\n",
    "prompt_infos = [\n",
    "    {\n",
    "        \"name\": \"naming\",\n",
    "        \"description\": \"擅长用中文起名字\",\n",
    "        \"prompt_template\": naming_template,\n",
    "    },\n",
    "    {\n",
    "        \"name\": \"math\",\n",
    "        \"description\": \"Good for answering math questions\",\n",
    "        \"prompt_template\": math_template,\n",
    "    },\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.llms import Tongyi\n",
    "import os\n",
    "os.environ[\"DASHSCOPE_API_KEY\"]= \"sk-9d8f1914800e497f8717144e860f99bc\"\n",
    "llm = Tongyi()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import ConversationChain\n",
    "from langchain.chains.router import MultiPromptChain\n",
    "\n",
    "# llm chains初始化\n",
    "destination_chains = {}\n",
    "for p_info in prompt_infos:\n",
    "    name = p_info[\"name\"]\n",
    "    prompt_template = p_info[\"prompt_template\"]\n",
    "    prompt = PromptTemplate(template=prompt_template, input_variables=[\"input\"])\n",
    "    chain = LLMChain(llm=llm, prompt=prompt)\n",
    "    destination_chains[name] = chain\n",
    "default_chain = ConversationChain(llm=llm, output_key=\"text\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains.router.llm_router import LLMRouterChain, RouterOutputParser\n",
    "from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE\n",
    "destinations = [f\"{p['name']}: {p['description']}\" for p in prompt_infos]\n",
    "destinations_str = \"\\n\".join(destinations)\n",
    "router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)\n",
    "router_prompt = PromptTemplate(\n",
    "    template=router_template,\n",
    "    input_variables=[\"input\"],\n",
    "    output_parser=RouterOutputParser(),\n",
    ")\n",
    "router_chain = LLMRouterChain.from_llm(llm, router_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "chain = MultiPromptChain(\n",
    "    router_chain=router_chain,\n",
    "    destination_chains=destination_chains,\n",
    "    default_chain=default_chain,\n",
    "    verbose=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(chain.run(\"给我一个很土但是听起来很好养活的男孩小名\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Sequential chain（串行）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = \"\"\"你是一个非常棒的起名专家.\\\n",
    "    你非常擅长给新生儿们起好听的，富含寓意的名字.\\\n",
    "    用中文给出3种回答.\n",
    "        \n",
    "    这里是问题：\n",
    "    {input}\"\"\"\n",
    "prompt_template = PromptTemplate(input_variables=[\"input\"], template=template)\n",
    "synopsis_chain = LLMChain(llm=llm, prompt=prompt_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = \"\"\"你是一个名字评论专家，你非常擅长给名字做分析，并且判断哪个名字更好.\n",
    "        \n",
    "    名字分析：\n",
    "    {synopsis}\n",
    "    对上面的名字进行分析，判断哪个更好：\"\"\"\n",
    "prompt_template = PromptTemplate(input_variables=[\"synopsis\"], template=template)\n",
    "review_chain = LLMChain(llm=llm, prompt=prompt_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "# This is the overall chain where we run these two chains in sequence.\n",
    "from langchain.chains import SimpleSequentialChain\n",
    "overall_chain = SimpleSequentialChain(chains=[synopsis_chain, review_chain], verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n",
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n",
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n",
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m1. 小石头：取自石头坚韧、耐磨损的特性，寓意孩子生命力顽强，能够经受生活的磨砺。\n",
      "\n",
      "2. 铁蛋：铁象征着坚强和耐磨，蛋则代表生命的初生与希望，名字寓意孩子身体健康，结实如铁，生活能力强。\n",
      "\n",
      "3. 牛牛：以牛为名，象征着勤劳、踏实、力大无穷的特质，寓意孩子未来会像牛一样健壮且勤奋，容易在生活上茁壮成长。\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n",
      "d:\\DevelopEnvironment\\python\\python 3.9.9\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:189: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[33;1m\u001b[1;3m每个名字都有其独特的寓意和美好祝愿，选择哪个名字更好，其实很大程度上取决于父母或取名人对孩子的期望以及个人喜好。下面是对三个名字的进一步评价：\n",
      "\n",
      "1. \"小石头\"：这个名字富有力量感，强调了坚韧不拔的精神品质，适合那些期待孩子具有坚定意志和顽强毅力的家庭。\n",
      "\n",
      "2. \"铁蛋\"：这个名字既体现了健康强壮的体魄，又寄寓了对未来生活能力的期许。对于希望孩子身体强健，面对困难有韧性且乐观向上的家庭来说，是个不错的选择。\n",
      "\n",
      "3. \"牛牛\"：这个名字通俗易懂，寓意孩子具备吃苦耐劳、脚踏实地的美好品格，同时也寄予了健康茁壮成长的愿望。对于那些崇尚勤劳美德，希望孩子能成为社会中坚力量的家庭，十分贴切。\n",
      "\n",
      "综上所述，没有绝对意义上的“更好”，每个名字都各有特色，蕴含着不同的寓意。家长可以根据自己对孩子未来的期望和个人喜好来做出最适合的选择。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "review = overall_chain.run(\"给我一个很土但是听起来很好养活的男孩小名\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
